import { Injectable, Logger } from "@nestjs/common";
import { BaseService } from '@/core/base.service';
import { InjectQueue } from '@nestjs/bull';
import { Queue } from 'bull';
import { UtilService } from '@/core/util.service';
import { AssetAutoSale, Prisma } from '@prisma/client';
import { BaseQueryDto } from '@/dtos';
import { AutoSaleStatusEnum, TokenStatusEnum } from '@/enums';
import { AssetAutoSaleUpdateDto } from '@/dtos/autosale.dto';
import { halt, ok } from '@/utils';

@Injectable()
export class AutosaleService extends BaseService {
  constructor(
    @InjectQueue('autosale')
    private readonly autoSaleQueue: Queue,
    private readonly utilService: UtilService,
  ) {
    super();
  }

  async serviceStart() {
    const sale = await this.autoSaleQueue.add('sale', null, {
      repeat: {
        every: 1 * 1000, // 每1s执行一次
      },
      // removeOnComplete: true,
      // delay: 10000, // 延迟10s
    });

    return true;
  }

  async serviceClose() {
    await this.utilService.cleanKeys(`bull:autosale:repeat`);
    console.log('关闭自动挂售');
    return true;
  }

  async query({
    params,
    sort,
  }: BaseQueryDto<Prisma.AssetAutoSaleWhereUniqueInput>) {
    const { current = 1, pageSize = 20, keyword, ...where } = params;

    let sql = `
      SELECT #{fields} FROM AssetAutoSale AS auto
      LEFT JOIN asset AS a ON auto.assetId = a.id
    `;

    const [{ count }] = await this.prisma.$queryRawUnsafe<[{ count: number }]>(
      sql.replace('#{fields}', 'COUNT(auto.id) AS count'),
    );

    const list = await this.prisma.$queryRawUnsafe<AssetAutoSale[]>(
      `${sql.replace(
        '#{fields}',
        'auto.id, auto.assetId, auto.sellerId, auto.minPrice, auto.maxPrice, auto.waitTime, auto.onceTime, a.title, a.image, ' +
          'auto.isIgnore, auto.createdAt, auto.status ',
      )}
      ORDER BY ${
        !!sort && Object.keys(sort).length > 0
          ? Object.entries(sort)
              .map(([k, v]) => `auto.${k} ${v === 'descend' ? 'DESC' : 'ASC'}`)
              .join(',')
          : 'auto.id DESC'
      }
      LIMIT ${pageSize} 
      OFFSET ${(current - 1) * pageSize}
      `,
    );

    const total = count ? Number(count) : 0;
    const totalPage = Math.ceil(total / pageSize);
    const hasMore = current < totalPage;

    const aStocks = [];
    for (const item of list) {
      aStocks[item.id] = await this.redis.scard(`autosale:${item.id}:queue`);
    }

    return {
      total,
      totalPage,
      hasMore,
      current,
      pageSize,
      list: list.map((o: any) => ({
        ...o,
        minPrice: Number(o.minPrice),
        maxPrice: Number(o.maxPrice),
        stocks: Number(aStocks[o.id]),
      })),
    };
  }

  // async detail(assetId: number) {
  //   return await this.prisma.assetAutoSale.findUnique({
  //     where: {
  //       assetId,
  //     },
  //   });
  // }

  async create(data: Prisma.AssetAutoSaleCreateInput): Promise<AssetAutoSale> {
    return this.prisma.assetAutoSale.create({
      data,
    });
  }

  async update(params: AssetAutoSaleUpdateDto): Promise<AssetAutoSale> {
    const { where, data } = params;
    return this.prisma.assetAutoSale.update({
      where,
      data,
    });
  }

  async cache(jobId: number, assetId: number, sellerId: number) {
    // 查询持仓
    const list = await this.prisma.token.findMany({
      where: {
        assetId,
        ownerId: sellerId,
      },
      select: {
        id: true,
      },
    });

    const ids = [];

    list.map((item) => {
      ids.push(item.id);
    });

    if (ids.length < 1) {
      throw Error('无可上架资产');
      // return false;
    }

    await this.redis.sadd('autosale:' + jobId + ':queue', ...ids);

    return true;
  }

  async clean(jobId: number) {
    const sIdsCacheKey = 'autosale:' + jobId + ':queue';
    await this.redis.del(sIdsCacheKey);

    return true;
  }

  async jobSwitch(id) {
    const job = await this.prisma.assetAutoSale.findFirst({
      where: {
        id: id,
      },
    });

    if (!job) {
      return halt('任务不存在');
    }

    let data = {
      status: 0,
    };

    if (job.status == AutoSaleStatusEnum.RUNNING) {
      await this.clean(id);
      data = {
        status: AutoSaleStatusEnum.COMPLETED,
      };
    }

    if (job.status == AutoSaleStatusEnum.WAIT) {
      try {
        await this.cache(job.id, job.assetId, job.sellerId);
      } catch (e) {
        return halt('开启失败：' + e);
      }

      data = {
        status: AutoSaleStatusEnum.RUNNING,
      };
    }

    if (data.status !== 0) {
      await this.prisma.assetAutoSale.update({
        where: {
          id: id,
        },
        data,
      });
    }

    return true;
  }
}
